`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@brief A small (32 element) LUTRAM based FIFO with both combinatorial and registered outputs.
 */
module SmallLutramFifo(
		clk,
		wr, din,
		rd, dout_c, dout_r,
		overflow, underflow, empty, full
		);
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// I/O and parameter declarations
	
	parameter WIDTH = 16;

	input wire clk;
	
	input wire wr;
	input wire[WIDTH-1:0] din;
	
	input wire rd;
	output wire[WIDTH-1:0] dout_c;			//combinatorial output
	output reg[WIDTH-1:0] dout_r = 0;		//registered output
	
	wire[WIDTH-1:0] dout_c_raw;
	
	output reg overflow = 0;
	output reg underflow = 0;	
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Control logic
	
	reg[4:0] rpos = 0;
	reg[4:0] wpos = 0;
	
	wire[4:0] irpos = rpos + 5'd1;
	wire[4:0] iwpos = wpos + 5'd1;
	
	output wire empty;
	assign empty = (rpos == wpos);	//if write pointer is at read pointer we're empty
	output wire full;
	assign full = (iwpos == rpos);	//if write pointer is about to hit read pointer we're full
	
	//loopback for write during read when empty
	assign dout_c = (wr & rd & empty) ? din : dout_c_raw;
	
	always @(posedge clk) begin
		
		dout_r <= 0;
		overflow <= 0;
		underflow <= 0;
		
		//Read only
		if(rd && !wr) begin
		
			//Empty? Can't do anything
			if(empty) begin
				underflow <= 1;
				dout_r <= { {(WIDTH-1){1'bx}}, 1'bx};
				$display("[SmallLutramFifo] %m WARNING: Underflow occurred");
			end
			
			//All is well, bump stuff
			else begin
				rpos <= irpos;
				dout_r <= dout_c;
			end
		end
		
		//Read+write
		else if(rd && wr) begin
		
			//Empty? Forward data
			if(empty) begin
				dout_r <= dout_c;
				rpos <= irpos;
				wpos <= iwpos;
			end
			
			//All's well, do a normal read + write
			else begin
				dout_r <= dout_c;
				
				rpos <= irpos;
				wpos <= iwpos;
			end
		
		end
		
		//Write only
		else if(!rd && wr) begin
			
			//Full? Error
			if(full) begin
				overflow <= 1;
				$display("[SmallLutramFifo] %m WARNING: Overflow occurred");
			end
			
			//No, just write
			else begin
				wpos <= iwpos;
			end
			
		end
		
	end

	////////////////////////////////////////////////////////////////////////////////////////////////
	// The memory

	LutramMacroDP #(.WIDTH(WIDTH)) ram (
		.clk(clk), 
		.porta_we(wr), 
		.porta_addr(wpos), 
		.porta_din(din), 
		//.porta_dout(unused_w_dout),
		.portb_addr(rpos), 
		.portb_dout(dout_c_raw)
	);
	
endmodule
